import {
  Component,
  Input,
  forwardRef,
  ViewChildren,
  ElementRef,
  ViewEncapsulation,
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Output,
  EventEmitter,
  OnInit,
  OnChanges,
} from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
import { BACKSPACE, LEFT_ARROW, NUMPAD_PERIOD, RIGHT_ARROW } from '@angular/cdk/keycodes';
import { InputBoolean, LvConfig, TypeUtils } from '../core/api';
import { MaxLengthEnum } from './interface';

@Component({
  selector: 'lv-input-ip, [lv-input-ip]',
  exportAs: 'lvInputIP',
  templateUrl: 'inputip.component.html',
  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush,
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef((): typeof InputIPComponent => InputIPComponent),
      multi: true,
    },
  ],
  host: {
    '[class.lv-input-ip]': 'true',
    '[class.lv-input-ip-block]': 'lvBlock',
    '[class.lv-input-ipv4-port]': 'lvShowPort',
    '[class.lv-input-ip-focus]': 'isFocus()',
    '[class.lv-input-ipv6]': "lvType === 'v6'",
    '[class.lv-input-ip-large]': "lvSize === 'large'",
    '[attr.disabled]': 'getWrapperDisabled()',
  },
})
export class InputIPComponent implements ControlValueAccessor, OnInit, OnChanges {
  @Input() lvType: 'v4' | 'v6' = 'v4';
  @Input() lvDisabled: boolean | number[] = false;
  @Input() lvSize: 'large' | 'default' = 'default';
  @ViewChildren('input', { read: ElementRef }) input;
  @Output() lvBlur: EventEmitter<any> = new EventEmitter();
  @Output() lvFocus: EventEmitter<any> = new EventEmitter();

  @Input() @InputBoolean() lvBlock = LvConfig.ipOptions.lvBlock || false;
  @Input() @InputBoolean() lvShowPort = LvConfig.ipOptions.lvShowPort || false; // 目前只有IPv4展示端口

  @Input() @InputBoolean() lvIsShorthand = LvConfig.ipOptions.lvIsShorthand || false; // IP是否简写

  public focusFlag;
  public inputList: any[];
  public IPValue: any[] = [];
  public portValue: string = '';
  public maxLengthEnum = MaxLengthEnum;
  private maxIndex: number;

  constructor(
    private el: ElementRef,
    private cdr: ChangeDetectorRef,
  ) {}

  private get IPValueString(): string {
    const joiner = this.lvType === 'v4' ? '.' : ':';
    return this.IPValue.join('') && this.IPValue.join(joiner);
  }

  registerOnChange(fn: any): void {
    this._onChange = fn;
  }

  registerOnTouched(fn: any): void {
    this._onTouch = fn;
  }

  /**
   * ngFor遍历的 trackBy函数，防止数据更新导致所有DOM重新渲染
   */
  public trackByFn(index: any): any {
    return index;
  }

  isFocus(): boolean {
    return (this.el.nativeElement as HTMLElement).querySelectorAll('input:focus').length !== 0;
  }

  getWrapperDisabled(): string {
    if (TypeUtils.isArray(this.lvDisabled)) {
      return null;
    } else {
      return this.lvDisabled ? '' : null;
    }
  }

  onPaste(event): void {
    if (!this.isFocus()) {
      return;
    }
    const data = event.clipboardData.getData('Text');
    this.writeValue(data, true);
  }

  getItemDisabled(i): number[] | boolean {
    if (TypeUtils.isArray(this.lvDisabled)) {
      return (this.lvDisabled as number[]).includes(i);
    } else {
      return this.lvDisabled;
    }
  }

  onFocus(event): void {
    event.target.select();
    if (!this.focusFlag) {
      const IPPortStr = this._setIPAndPortStr();
      this.lvFocus.emit(IPPortStr);
      this.focusFlag = true;
    }
  }

  isIpv4(value): any {
    // tslint:disable-next-line
    const reg =
      /^(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)$/i;
    return reg.test(value) ? value : '...';
  }

  ngOnInit(): void {
    if (this.lvType === 'v4') {
      this.inputList = ['', '', '', ''];
    } else {
      this.inputList = ['', '', '', '', '', '', '', ''];
    }

    this.maxIndex = this._hasIPv4Port() ? this.inputList.length : this.inputList.length - 1;
  }

  ngOnChanges(changes): void {
    if (changes.lvType) {
      if (this.lvType === 'v4') {
        this.inputList = ['', '', '', ''];
      } else {
        this.inputList = ['', '', '', '', '', '', '', ''];
      }
      this.writeValue('', false);
      const IPPortStr = this._setIPAndPortStr();
      this._onChange(IPPortStr);
      this.maxIndex = this._hasIPv4Port() ? this.inputList.length : this.inputList.length - 1;
    }
  }

  /**
   * 给每一个ip的输入框赋值
   * @param value ip值
   */
  setInputValue(value: string, portValue: string, isPaste = false): void {
    const inputArray = value.split(this.lvType === 'v4' ? '.' : ':');
    if (isPaste && !this.checkPastedData([...inputArray, portValue])) {
      return;
    }
    this.IPValue = [];
    inputArray.forEach((item): void => {
      this.IPValue.push(item);
    });
    this.portValue = portValue;
  }

  writeValue(value: any, isPaste = false): void {
    if (value) {
      let IPValue = value;
      let portValue = '';
      if (this._hasIPv4Port()) {
        [IPValue, portValue] = value.split(':');
      }
      const _value = this.lvType === 'v4' ? this.isIpv4(IPValue) : this.isIpv6(IPValue);
      this.setInputValue(_value, portValue, isPaste);
    } else {
      this.setInputValue('', '', isPaste);
    }
    this.cdr.markForCheck();
  }

  onPortInput(event): void {
    if (event.inputType === 'insertFromPaste') {
      event.currentTarget.value = this.portValue;
    }

    const value = event.target.value.trim();

    // 端口非数字输入重置为空,数字大于65535，重置为65535
    if (/\d+/.test(value)) {
      if (/^\d+$/.test(value)) {
        const inputMaxValue = 65535;
        this.portValue = value > inputMaxValue ? String(inputMaxValue) : value;
      }
    } else {
      this.portValue = '';
    }
    event.currentTarget.value = this.portValue;

    this._onChange(this.getIpPortStr());
  }

  onBlur(): void {
    this._onTouch();
    setTimeout((): void => {
      if (!this.isFocus()) {
        const value = this.lvIsShorthand ? this.mask(this.IPValueString) : this.IPValueString;
        this.IPValue = [];
        this.setInputValue(value, this.portValue);
        if (this.lvIsShorthand) {
          this.portValue = this.portValue.replace(/^0+/g, '') === '' ? '0' : this.portValue.replace(/^0+/g, '');
        }
        const IPPortStr = this._setIPAndPortStr();
        this._onChange(IPPortStr);
        this.lvBlur.emit(IPPortStr);

        this.focusFlag = false;
      }
    });
  }

  isIpv6(value): any {
    // tslint:disable-next-line
    const reg =
      /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/i;
    return reg.test(value) ? value : ':::::::';
  }

  onInput(event, i): void {
    if (event.inputType === 'insertFromPaste') {
      event.currentTarget.value = this.IPValue[i];
    }

    const value = event.target.value.trim();

    if (this.lvType === 'v4') {
      // IPv4非数字输入重置为空,数字大于255，重置为255
      if (/\d+/.test(value)) {
        if (/^\d+$/.test(value)) {
          const inputMaxValue = 255;
          this.IPValue[i] = value > inputMaxValue ? String(inputMaxValue) : value;
        }
      } else {
        this.IPValue[i] = '';
      }
      event.currentTarget.value = this.IPValue[i];
      if (event.currentTarget.value.length >= 3 && i < this.maxIndex) {
        this.input._results[i + 1].nativeElement.focus();
      }
    } else if (this.lvType === 'v6') {
      if (/[0-9a-fA-F]+/.test(value)) {
        if (/^[0-9a-fA-F]+$/.test(value)) {
          this.IPValue[i] = value;
        }
      } else {
        this.IPValue[i] = '';
      }
      event.currentTarget.value = this.IPValue[i];
      if (event.currentTarget.value.length >= 4 && i < this.maxIndex) {
        this.input._results[i + 1].nativeElement.focus();
      }
    }
    const IPPortStr = this._setIPAndPortStr();
    this._onChange(IPPortStr);
  }

  // 端口input的i为4
  onKeydown(event, i = 4): void {
    const key = event.keycode || event.which;

    const PERIOD = 190; // 190代表 >.
    // 当输入‘.’时，自动跳至下一输入框中,并选中该输入框中的值
    if ((key === PERIOD || key === NUMPAD_PERIOD) && event.target.value) {
      if (i < this.maxIndex) {
        const nextInput = this.input._results[i + 1].nativeElement;
        nextInput.focus();
        nextInput.select();
      }

      event.preventDefault(); // 不论是否为最后一个输入框,防止默认事件发生,否则输入框中会出现 ‘.’
      return;
    }

    // 相邻的输入框响应键盘的right和left
    if (key === RIGHT_ARROW && event.target.selectionStart === event.target.value.length && i < this.maxIndex) {
      const nextInput = this.input._results[i + 1].nativeElement;
      nextInput.setSelectionRange(0, 0);
      setTimeout((): void => {
        nextInput.focus();
      });
    }

    if (key === LEFT_ARROW && event.target.selectionStart === 0 && i > 0) {
      const previousInput = this.input._results[i - 1].nativeElement;
      previousInput.setSelectionRange(previousInput.value.length, previousInput.value.length);
      setTimeout((): void => {
        previousInput.focus();
      });
    }

    // 删除
    if (key === BACKSPACE && event.target.value.length === 0 && i > 0) {
      const previousInput = this.input._results[i - 1].nativeElement;
      previousInput.setSelectionRange(previousInput.value.length, previousInput.value.length);
      setTimeout((): void => {
        previousInput.focus();
      });
    }
  }

  private _onTouch: any = (): void => {};

  private _onChange: any = (): void => {};

  private _hasIPv4Port(): boolean {
    return this.lvType === 'v4' && this.lvShowPort;
  }

  private _setIPAndPortStr(): string {
    return this._hasIPv4Port() ? this.getIpPortStr() : this.IPValueString;
  }

  private getIpPortStr(): string {
    return !this.IPValueString && !this.portValue ? '' : `${this.IPValueString}:${this.portValue}`;
  }

  /**
   * 判断粘贴过来的数据是否符合禁用规则
   * @param dataArr
   * @returns
   */
  private checkPastedData(dataArr: string[]): boolean {
    if (this.lvDisabled) {
      if (Array.isArray(this.lvDisabled)) {
        const comparedArr = [...this.IPValue, this.portValue];
        for (const index of this.lvDisabled) {
          if (dataArr[index] !== comparedArr[index]) {
            return false;
          }
        }
      } else {
        return false;
      }
    }
    return true;
  }

  /**
   * @description IP需要去除前面的0，例如：,“012.12.23.002”经过该函数处理后变为：“12.12.23.2”
   * @param: ip ip字符串
   */
  private mask(ip: string): string {
    // 非ipV4直接返回当前值，不做处理
    const separator = this.lvType === 'v4' ? '.' : ':';
    const part = ip.split(separator);
    const partLength = part.length;
    for (let i: number = 0; i < partLength; i++) {
      let partNumber;
      if (part[i] !== '') {
        if (this.lvType === 'v4') {
          partNumber = parseInt(part[i], 10); // 将part[j]转化为整数，目的是消除前面的0
          partNumber /= 1;
        } else {
          partNumber = part[i].replace(/^0+/g, '') === '' ? 0 : part[i].replace(/^0+/g, '');
        }
        part[i] = `${partNumber}`; // 再转化为字符串
      }
    }
    return part.join(separator);
  }
}
